State and streams topic
Read what the player is doing, and react when it changes.
State and stream
The player shows its state in two ways:
player.stateis an immutable snapshot that you read synchronously.player.streamholds one stream per value, forStreamBuilderorlisten().
// Read once, in a handler or in build()
final volume = player.state.volume;
// Follow every change
player.stream.volume.listen((v) => print('volume $v'));
// Wait for the next change only
final next = await player.stream.volume.skip(1).first;
A state stream gives each new listener the current value first, then every change. A StreamBuilder on it needs no initialData:
StreamBuilder<Duration>(
stream: player.stream.position,
builder: (context, snapshot) => Text('${snapshot.data}'),
);
Event streams, such as endFile, error and log, deliver only what happens after listen().
A few values live on one side only. playbackState, prefetchState, prefetchCacheDuration, waveform, loudnessScan and the event streams, fft, pcm and loudnessMeter among them, have no field in state. tlsCaFile, readError and skippedSegments have no stream.
Current entry
final s = player.state;
// index is -1 while openAll still builds the queue
final i = s.playlist.index;
if (i >= 0 && i < s.playlist.items.length) {
print(s.playlist.items[i].uri);
}
Playback state
playbackState folds playing, buffering, completed, pausedForCache and the loaded file into one value, for a single indicator.
player.stream.playbackState.listen((phase) {
switch (phase) {
case MpvPlaybackState.idle: // no file loaded
case MpvPlaybackState.loading: // a file opens
case MpvPlaybackState.buffering: // waits for the network during playback
case MpvPlaybackState.playing: // produces audio
case MpvPlaybackState.paused: // a file is loaded, no audio
case MpvPlaybackState.completed: // the last entry ended, no loop on
}
});
A paused live stream is paused, not idle.
Which flag to use
| Value | Use it for |
|---|---|
playWhenReady |
The play and pause button. Seeks and buffering leave it unchanged |
playing |
A spinner. It turns false during seeks and buffering |
playWhenReady && playing |
Audio comes out now |
completed |
The end of the last entry. It stays false between entries and while a loop is on |
buffering |
A file opens. A stall during playback shows on pausedForCache |
cacheBufferingState |
A buffering indicator, from 0 to 100 |
bufferingPercentage compares the cache with state.cache.secs. It stays near 0 with the default cache size, so prefer cacheBufferingState or bufferDuration against your own target.
duration is Duration.zero for a live stream and while it is unknown. position updates at most about 30 times a second.
Streams
| Group | Some streams | What for |
|---|---|---|
| Playback | position, duration, volume, rate, pitch, seeking |
Controls and the progress bar |
| Playlist and tracks | playlist, loop, shuffle, tracks, chapters |
The queue and its entries |
| Output | audioDevice, audioDevices, audioParams, audioOutParams, systemVolume |
Devices and the format that plays |
| Effects | audioEffects, replayGain, gapless |
The effects chain |
| Network and cache | cache, pausedForCache, cacheSpeed, demuxerCacheState |
Buffering and download speed |
| File | metadata, coverArt, mediaTitle, fileFormat, fileSize, path |
Tags and file details |
| Timing | audioPts, timeRemaining, playtimeRemaining |
Time left, with or without the rate |
| A-B loop | abLoopA, abLoopB, abLoopCount, remainingAbLoops |
The loop section |
| Analysis | fft, pcm, waveform, loudnessScan, loudnessMeter |
Visualizers and meters |
| Media session | mediaSession, mediaSessionCommands |
The OS controls |
| Events | seekCompleted, endFile, error, log, internalLog, hook |
Things that happen once |
Most setters have a stream of the same name, so setRate changes rate. The API reference of PlayerStream and PlayerState lists every value with its docs.
A null field means the value is missing, and the field's docs say what that means. systemVolume is null on an output without a system volume, abLoopCount is null for an endless loop, and readError is null while completed is false.
abLoopA and abLoopB are null while that point is off. They return to null when the file they were set on ends. A point set with no file loaded stays for every file.
See the Errors and logs, Visualizer and analysis and Media session topics for the event streams.
Prefetch
With setPrefetchPlaylist(true), the player opens the next entry in the background before the current one ends. prefetchState follows that work. See the Playback topic to set up prefetch.
| State | Meaning |
|---|---|
idle |
No prefetch runs |
loading |
The next entry opens and fills its cache |
ready |
The next entry is open, and the next change of entry uses it |
used |
The entry started from the prefetch. It stays until the next loading, or until a cancel resets it to idle |
failed |
The next entry could not open. It stays until the next loading or a stop |
player.stream.prefetchState.listen((state) {
if (state == PrefetchState.failed) print('Prefetch failed');
});
// How much of the next entry is cached, zero while nothing is prefetched
player.stream.prefetchCacheDuration.listen((buffered) {
const target = Duration(seconds: 30);
final progress = (buffered.inMilliseconds / target.inMilliseconds).clamp(0.0, 1.0);
showPrefetchProgress(progress);
});
Classes
- PlayerState State and streams
- Immutable snapshot of the Player's complete playback state.
- PlayerStream State and streams
- Typed streams of the Player's state and events.